import argparse
import json
import os
from abc import ABC, abstractmethod
from dataclasses import dataclass, field
from typing import Dict, Any, Optional

from engine_server.utils.ip import ip_valid_check, port_valid_check
from engine_server.utils.validators import FileValidator

supported_engine = ["vllm"]

@dataclass
class ServerConfig:
    server_host: str = "127.0.0.1"
    server_port: int = 9001
    engine_type: str = "vllm"
    config_path: Optional[str] = None
    dp_rank: int = 0

    def validate(self):
        if self.engine_type not in supported_engine:
            raise ValueError(f"{self.engine_type} is not supported.")
        ip_valid_check(self.server_host)
        port_valid_check(int(self.server_port))
        if self.dp_rank < 0 or self.dp_rank > 65535:
            raise ValueError(f"{self.dp_rank} is not supported.")
        if not os.path.exists(self.config_path):
            raise ValueError(f"config file {self.config_path} does not exist")
        if not FileValidator(self.config_path) \
            .check_not_soft_link().check_file_size().check().is_valid():
            raise ValueError(f"{self.config_path} is not a valid file path.")

class IConfig(ABC):
    @abstractmethod
    def validate(self):
        pass

    @abstractmethod
    def convert(self):
        pass

    @abstractmethod
    def get_args(self)->argparse.Namespace:
        pass

    @abstractmethod
    def get_server_config(self)->ServerConfig:
        pass


@dataclass
class BaseConfig(IConfig):
    server_config: ServerConfig
    kv_config: Dict[str, Any] = field(default_factory=dict)

    def validate(self) :
        self.server_config.validate()

    def _load_config_file(self) -> None:
        try:
            with open(self.server_config.config_path, 'r', encoding='utf-8') as f:
                self.kv_config.update(json.load(f))
        except Exception as e:
            raise ValueError(f"failed to load config file: {str(e)}")

    def convert(self):
        self._load_config_file()

    def get_args(self)->argparse.Namespace:
        return argparse.Namespace(**self.kv_config)

    def get_server_config(self)->ServerConfig:
        return ServerConfig(**self.kv_config)



